package com.settlement.system.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.settlement.system.common.enums.ReturnStatusEnum;
import com.settlement.system.common.exception.ServiceException;
import com.settlement.system.common.util.SecurityUtils;
import com.settlement.system.common.util.common.BeanValidator;
import com.settlement.system.common.util.common.CommonAcsUtil;
import com.settlement.system.common.util.common.SystemUserUtil;
import com.settlement.system.mapper.BaseMapper;
import com.settlement.system.mapper.TblOrderAuditBillDtlMapper;
import com.settlement.system.mapper.TblOrderAuditBillMapper;
import com.settlement.system.mapper.security.userdetails.SysUserDetails;
import com.settlement.system.model.entity.common.*;
import com.settlement.system.reply.ObjectDataResponse;
import com.settlement.system.service.ITblAcsRoleBillStatusService;
import com.settlement.system.service.ITblAcsUserRoleAuthorityService;
import com.settlement.system.service.ITblBillResponsibleReasonService;
import com.settlement.system.service.ITblOrderAuditBillDtlService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;

/**
 * 订单稽核单据明细表 服务实现类
 *
 * @author 小船
 * @since 2020-10-21
 */
@Slf4j
@Service
public class TblOrderAuditBillDtlServiceImpl extends BaseServiceImpl implements ITblOrderAuditBillDtlService {

    @Resource
    private TblOrderAuditBillDtlMapper tblOrderAuditBillDtlMapper;

    @Resource
    private TblOrderAuditBillMapper tblOrderAuditBillMapper;

    @Resource
    private ITblAcsUserRoleAuthorityService tblAcsUserRoleAuthorityService;

    @Resource
    private ITblAcsRoleBillStatusService tblAcsRoleBillStatusService;

    @Resource
    private ITblBillResponsibleReasonService tblBillResponsibleReasonService;

    @Override
    public BaseMapper init() {
        return tblOrderAuditBillDtlMapper;
    }

    @Override
    public List<TblOrderAuditBillDtl> selectRoleStatus(Map<String, Object> params) throws ServiceException {
        try {
            return tblOrderAuditBillDtlMapper.selectRoleStatus(params);
        } catch (Exception e) {
            throw new ServiceException(e);
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = ServiceException.class)
    public void insertDtl(TblOrderAuditBill bill, TblOrderAuditBillDtl currentDtl) throws ServiceException {
        try {
            //插入操作日志
            tblOrderAuditBillDtlMapper.insert(currentDtl);
            //更新主表信息
            tblOrderAuditBillMapper.updateByBillNo(bill);

            //如果单据归档，需要更新缓存表结束方式
//            if(StringUtils.equals("归档",currentDtl.getBillStatusName())){
//                tblRefundAuditBillMapper.updateRefundAuditCache(3,currentDtl.getBillNo());
//            }
        } catch (Exception e) {
            throw new ServiceException("新增数据异常,数据已经回滚", e);
        }
    }

    /**
     * 更新主表和明细表数据，分情况进行处理
     *
     * @param user   用户信息
     * @param billNo 退款稽核单据
     * @throws ServiceException
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = ServiceException.class)
    public void updateBillStatus(SysUserDetails user, String billNo) throws ServiceException {
        try {
            Map<String, Object> params = new HashMap<>(16);
            params.put("billNo", billNo);
            List<TblOrderAuditBillDtl> allList = tblOrderAuditBillDtlMapper.selectByParam(params);
            List<TblOrderAuditBill> mainList = tblOrderAuditBillMapper.selectByParam(params);
            TblOrderAuditBill bill = new TblOrderAuditBill();

            params.put("id", mainList.get(0).getDealDtlId());
            List<TblOrderAuditBillDtl> dealDtlList = tblOrderAuditBillDtlMapper.selectByParam(params);

            params.put("id", dealDtlList.get(0).getLastEffectiveId());
            List<TblOrderAuditBillDtl> lastEfficetList = tblOrderAuditBillDtlMapper.selectByParam(params);
            PropertyUtils.copyProperties(bill, lastEfficetList.get(0));

            TblOrderAuditBillDtl currenDtl = dealDtlList.get(0);
            currenDtl.setUpdateUser(user.getUsername());
            currenDtl.setUpdateTime(new Date());
            currenDtl.setCreateUser(user.getUsername());
            currenDtl.setCreateTime(new Date());
            currenDtl.setId(CommonAcsUtil.generateUUId());
            currenDtl.setStatusName("撤销");
            currenDtl.setOrderField(allList.get(0).getOrderField() + 1);

            bill.setUpdateUser(user.getUsername());
            bill.setUpdateTime(new Date());
            bill.setDealDtlId(lastEfficetList.get(0).getId());

            //TblRefundAuditBillDtl lastDtl = new TblRefundAuditBillDtl();
            //lastDtl.setId(mainList.get(0).getDealDtlId());
            //lastDtl.setStatusName("撤销");

            //更新主表信息
            tblOrderAuditBillMapper.updateByBillNo(bill);
            //更新最后一条数据为撤销
            //tblRefundAuditBillDtlMapper.update(lastDtl);
            //新增待处理明细
            tblOrderAuditBillDtlMapper.insert(currenDtl);

        } catch (Exception e) {
            throw new ServiceException("撤销数据异常", e);
        }
    }


    @Override
    public List<TblOrderAuditBillDtl> selectLastSecond(Map<String, Object> params) throws ServiceException {
        try {
            return tblOrderAuditBillDtlMapper.selectLastSecond(params);
        } catch (Exception e) {
            throw new ServiceException(e);
        }
    }

    @Override
    public Map<String, Object> batchSaveDtl(TblOrderAuditBillDtl tblOrderAuditBillDtl) throws ServiceException {
        Map<String, Object> resultMap = new HashMap<String, Object>(16);
        ArrayList<String> billNoList = new ArrayList<String>();
        char charEnglishComma = ',';
        if (StringUtils.indexOf(tblOrderAuditBillDtl.getBillNo(), charEnglishComma) != -1) {
            String[] billNoArr = tblOrderAuditBillDtl.getBillNo().split(",");
            for (String billNo : billNoArr) {
                billNoList.add(billNo);
            }
        } else {
            billNoList.add(tblOrderAuditBillDtl.getBillNo());
        }
        ArrayList<String> succList = new ArrayList<String>();
        ArrayList<String> failList = new ArrayList<String>();
        boolean resultFlag = false;
        if (billNoList != null && billNoList.size() > 0) {
            for (String billNo : billNoList) {
                tblOrderAuditBillDtl.setBillNo(billNo);
                resultFlag = saveOrderCheckDtl(tblOrderAuditBillDtl);
                if (resultFlag) {
                    succList.add(billNo);
                } else {
                    failList.add(billNo);
                }
            }
        }
        log.info("批量处理订单稽核单据，处理完成，返回结果succNum={},succList={},failNum={},failList={}", succList.size(), succList, failList.size(), failList);
        resultMap.put("succNum", succList.size());
        resultMap.put("failNum", failList.size());
        return resultMap;
    }

    private boolean saveOrderCheckDtl(TblOrderAuditBillDtl tblOrderAuditBillDtl) {
        String billNo = tblOrderAuditBillDtl.getBillNo();
        if (StringUtils.isEmpty(billNo)) {
            log.error("批量处理订单稽核单据，单据编码不能为空，请核实");
            return false;
        }
        try {
            Map<String, Object> paramMap = new HashMap<>(16);
            paramMap.put("billNo", billNo);
            List<TblOrderAuditBillDtl> billList = selectRoleStatus(paramMap);
            if (CollectionUtils.isEmpty(billList)) {
                log.error("批量处理订单稽核单据，单据编码{}已经被归档，不允许在进行操作，请核实", billNo);
                return false;
            }
            SysUserDetails user = SecurityUtils.getUser();;
            //判断下最新一条记录是不是进行撤销用户所属角色，并且用户具有写的权限
            Map<String, Object> paramsUser = new HashMap<>(16);
            paramsUser.put("roleNo", billList.get(0).getRoleNo());
            paramsUser.put("authorityNo", "auth_002");
            paramsUser.put("loginName", user.getUsername());
            List<TblAcsUserRoleAuthority> auth = tblAcsUserRoleAuthorityService.selctAllUserInfo(paramsUser);
            if (CollectionUtils.isEmpty(auth)) {
                log.error("批量处理订单稽核单据，单据编码{}的状态已经与你不匹配，请确认当前单据是否已经被处理！", billNo);
                return false;
            }
            //校验完成，开始处理
            TblOrderAuditBill tblOrderAuditBill = new TblOrderAuditBill();
            //属性赋值
            PropertyUtils.copyProperties(tblOrderAuditBill, tblOrderAuditBillDtl);
            Map<String, Object> billParams = new HashMap<>(16);
            billParams.put("billNo", tblOrderAuditBillDtl.getBillNo());
            List<TblOrderAuditBill> orderAuditBillList = tblOrderAuditBillMapper.selectByParam(billParams);
            if (!CollectionUtils.isEmpty(orderAuditBillList)) {
                if (StringUtils.isEmpty(orderAuditBillList.get(0).getFirstServicePerson())) {
                    tblOrderAuditBill.setFirstServicePersonName(user.getUsername());
                    tblOrderAuditBill.setFirstServicePerson(user.getUsername());
                }
            }
            //单据明细
            tblOrderAuditBillDtl.setId(CommonAcsUtil.generateUUId());
            tblOrderAuditBillDtl.setCreateTime(new Date());
            tblOrderAuditBillDtl.setCreateUser(user.getUsername());
            tblOrderAuditBillDtl.setResponsiblePerson(user.getUsername());
            //单据主表
            tblOrderAuditBill.setDealDtlId(tblOrderAuditBillDtl.getId());
            tblOrderAuditBill.setUpdateTime(new Date());
            tblOrderAuditBill.setUpdateUser(user.getUsername());
            tblOrderAuditBill.setResponsiblePerson(user.getUsername());

            billParams.put("billStatusNo", tblOrderAuditBillDtl.getOrderBillStatusNo());
            List<TblAcsRoleBillStatus> acsRoleBillStatusList = tblAcsRoleBillStatusService.selectByParam(billParams);
            tblOrderAuditBillDtl.setRoleNo(acsRoleBillStatusList.get(0).getRoleNo());
            tblOrderAuditBillDtl.setStatusName("确认");
            tblOrderAuditBillDtl.setUpdateTime(new Date());
            tblOrderAuditBillDtl.setUpdateUser(user.getUsername());

            List<TblOrderAuditBillDtl> orderAuditBillDtlList = tblOrderAuditBillDtlMapper.selectByParam(billParams);
            tblOrderAuditBillDtl.setOrderField(orderAuditBillDtlList.get(0).getOrderField() + 1);
            tblOrderAuditBillDtl.setLastEffectiveId(orderAuditBillList.get(0).getDealDtlId());
            //保存操作
            insertDtl(tblOrderAuditBill, tblOrderAuditBillDtl);
            log.info("批量处理订单稽核单据成功===true，单据编码billNo={}", billNo);
            return true;
        } catch (Exception e) {
            log.error("批量处理订单稽核单据异常，单据编码为{}", billNo);
            return false;
        }
    }

    @Override
    public ObjectDataResponse importFile(MultipartFile file, HttpServletRequest request) {
        String errorMessage = null;
        List<String> errorMessageList = null;
        try {
            ImportDataListener listener = new ImportDataListener();
            ExcelReaderBuilder builder = EasyExcel.read(file.getInputStream(), TblOrderAuditBillDtlVo.class, listener);
            builder.doReadAll();
            errorMessage = listener.getErrorMessage();
            if (listener.rowCount == 0) {
                errorMessage = "导入内容为空";
            }
        } catch (Exception ex) {
            log.error("订单稽核单据处理，导入转化出错", ex);
            errorMessage = "系统异常,请联系管理员";
        }
        if (StringUtils.isEmpty(errorMessage)) {
            return new ObjectDataResponse(ReturnStatusEnum.IMPORT_SUCCESS.getValue(), "导入成功");
        }
        errorMessageList = new ArrayList<>();
        errorMessageList.add(errorMessage);
        return new ObjectDataResponse<List>(errorMessageList, ReturnStatusEnum.IMPORT_ERROR.getValue(), errorMessage);
    }

    /**
     * 导入数据的监听器
     */
    public class ImportDataListener<ModelType> extends AnalysisEventListener<ModelType> {
        private String errorMessage = null;
        private List<TblOrderAuditBillDtlVo> dataList = new ArrayList<TblOrderAuditBillDtlVo>();
        private int rowCount = 0;

        @Override
        public void invoke(ModelType modelType, AnalysisContext analysisContext) {
            modelType = BeanValidator.clearBeanStringBlank(modelType);
            if (modelType == null) {
                return;
            }
            final String shiwuzhuihui = "实物追回";
            final String huokuanzhuihui = "货款追回";
            TblOrderAuditBillDtlVo tblOrderAuditBillDtlVo = (TblOrderAuditBillDtlVo) modelType;
            if (StringUtils.isBlank(tblOrderAuditBillDtlVo.getBillNo())
                    || StringUtils.isBlank(tblOrderAuditBillDtlVo.getLossReasonName())
                    || StringUtils.isBlank(tblOrderAuditBillDtlVo.getLossReasonDtlName())
                    || StringUtils.isBlank(tblOrderAuditBillDtlVo.getResponsibleResults())) {
                errorMessage = "第" + (dataList.size() + 2) + "行数据，有必填项，请核实";
            }
            if (StringUtils.equals(tblOrderAuditBillDtlVo.getLossReasonName(), shiwuzhuihui)) {
                if (tblOrderAuditBillDtlVo.getQualityDate() == null
                        || StringUtils.isBlank(tblOrderAuditBillDtlVo.getQualityBillNo())
                        || tblOrderAuditBillDtlVo.getQualityQty() == null) {
                    errorMessage = "第" + (dataList.size() + 2) + "行数据，有必填项，请核实";
                }
            }
            if (StringUtils.equals(tblOrderAuditBillDtlVo.getLossReasonName(), huokuanzhuihui)) {
                if (tblOrderAuditBillDtlVo.getPaymentTime() == null
                        || StringUtils.isBlank(tblOrderAuditBillDtlVo.getCollectionTransactionNo())
                        || tblOrderAuditBillDtlVo.getReceivingAmount() == null) {
                    errorMessage = "第" + (dataList.size() + 2) + "行数据，有必填项，请核实";
                }
            }
            if (StringUtils.isBlank(errorMessage)) {
                Map<String, Object> paramMap = new HashMap<String, Object>(16);
                paramMap.put("lossReasonName", tblOrderAuditBillDtlVo.getLossReasonName());
                paramMap.put("lossReasonDtlName", tblOrderAuditBillDtlVo.getLossReasonDtlName());
                try {
                    List<TblBillResponsibleReason> responsibleReasonList = tblBillResponsibleReasonService.getResponsibleReasonByParam(paramMap);
                    if (responsibleReasonList != null && responsibleReasonList.size() > 0) {
                        tblOrderAuditBillDtlVo.setLossReasonNo(responsibleReasonList.get(0).getLossReasonNo());
                        tblOrderAuditBillDtlVo.setLossReasonDtlNo(responsibleReasonList.get(0).getLossReasonDtlNo());
                        tblOrderAuditBillDtlVo.setOrderBillStatusNo(responsibleReasonList.get(0).getOrderBillStatusNo());
                        tblOrderAuditBillDtlVo.setOrderBillStatusName(responsibleReasonList.get(0).getOrderBillStatusName());
                        tblOrderAuditBillDtlVo.setResponsibleNo(responsibleReasonList.get(0).getResponsibleNo());
                        tblOrderAuditBillDtlVo.setResponsibleName(responsibleReasonList.get(0).getResponsibleName());
                    } else {
                        errorMessage = "第" + (dataList.size() + 2) + "行数据，损失原因与损失原因细则名称不匹配";
                    }
                } catch (Exception e) {
                    log.error("订单稽核单据处理，导入处理异常", e);
                }
            }
            dataList.add(tblOrderAuditBillDtlVo);
            rowCount++;
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
            try {
                batchSaveImportData(dataList);
                dataList.clear();
            } catch (Exception e) {
                log.error("订单稽核单据处理，批量导入保存失败", e);
                if (StringUtils.isEmpty(e.getMessage())) {
                    errorMessage = "导入异常，请联系管理管理员";
                } else {
                    errorMessage = e.getMessage();
                }
            }
        }

        @Override
        public boolean hasNext(AnalysisContext context) {
            if (StringUtils.isEmpty(errorMessage)) {
                return true;
            }
            return false;
        }

        public String getErrorMessage() {
            return errorMessage;
        }
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {ServiceException.class, Exception.class})
    public void batchSaveImportData(List<TblOrderAuditBillDtlVo> dataList) throws Exception {
        log.info("订单稽核单据处理，批量导入数据，dataList={}", dataList);
        ArrayList<String> succList = new ArrayList<String>();
        ArrayList<String> failList = new ArrayList<String>();
        if (dataList != null && dataList.size() > 0) {
            String orderBillStatusNo = "";
            String orderBillStatusName = "";
            Map<String, Object> paramsMap = new HashMap<String, Object>(16);
            paramsMap.put("billStatusName", "待财务调账处理");
            List<TblAcsRoleBillStatus> tblAcsRoleBillStatusList = tblAcsRoleBillStatusService.selectByParam(paramsMap);
            if (tblAcsRoleBillStatusList != null && tblAcsRoleBillStatusList.size() > 0) {
                orderBillStatusNo = tblAcsRoleBillStatusList.get(0).getBillStatusNo();
                orderBillStatusName = tblAcsRoleBillStatusList.get(0).getBillStatusName();
            }
            TblOrderAuditBillDtl tblOrderAuditBillDtl;
            for (TblOrderAuditBillDtlVo tblOrderAuditBillDtlVo : dataList) {
                tblOrderAuditBillDtl = new TblOrderAuditBillDtl();
                tblOrderAuditBillDtlVo.setChannelName(null);
                tblOrderAuditBillDtlVo.setChannelNo(null);
                if (tblOrderAuditBillDtlVo.getIsLoss() == null) {
                    tblOrderAuditBillDtlVo.setIsLoss(0);
                }
                if (tblOrderAuditBillDtlVo.getIsLoss() == 1) {
                    tblOrderAuditBillDtlVo.setOrderBillStatusNo(orderBillStatusNo);
                    tblOrderAuditBillDtlVo.setOrderBillStatusName(orderBillStatusName);
                }
                PropertyUtils.copyProperties(tblOrderAuditBillDtl, tblOrderAuditBillDtlVo);
                String billNo = tblOrderAuditBillDtl.getBillNo();
                if (StringUtils.isEmpty(billNo)) {
                    log.error("订单稽核单据处理，批量导入数据，单据编码不能为空，请核实");
                    continue;
                }
                Map<String, Object> paramMap = new HashMap<>(16);
                paramMap.put("billNo", billNo);
                List<TblOrderAuditBillDtl> billList = selectRoleStatus(paramMap);
                if (CollectionUtils.isEmpty(billList)) {
                    log.error("订单稽核单据处理，批量导入数据，单据编码{}已经被归档，不允许在进行操作，请核实", billNo);
                    failList.add(billNo);
                    continue;
                }
                SysUserDetails user = SecurityUtils.getUser();;
                //判断下最新一条记录是不是进行撤销用户所属角色，并且用户具有写的权限
                Map<String, Object> paramsUser = new HashMap<>(16);
                paramsUser.put("roleNo", billList.get(0).getRoleNo());
                paramsUser.put("authorityNo", "auth_002");
                paramsUser.put("loginName", user.getUsername());
                List<TblAcsUserRoleAuthority> auth = tblAcsUserRoleAuthorityService.selctAllUserInfo(paramsUser);
                if (CollectionUtils.isEmpty(auth)) {
                    log.error("订单稽核单据处理，批量导入数据，单据编码{}的状态已经与你不匹配，请确认当前单据是否已经被处理！", billNo);
                    failList.add(billNo);
                    continue;
                }
                //校验完成，开始处理
                TblOrderAuditBill tblOrderAuditBill = new TblOrderAuditBill();
                //属性赋值
                PropertyUtils.copyProperties(tblOrderAuditBill, tblOrderAuditBillDtl);
                Map<String, Object> billParams = new HashMap<>(16);
                billParams.put("billNo", tblOrderAuditBillDtl.getBillNo());
                List<TblOrderAuditBill> orderAuditBillList = tblOrderAuditBillMapper.selectByParam(billParams);
                if (!CollectionUtils.isEmpty(orderAuditBillList)) {
                    if (StringUtils.isEmpty(orderAuditBillList.get(0).getFirstServicePerson())) {
                        tblOrderAuditBill.setFirstServicePersonName(user.getUsername());
                        tblOrderAuditBill.setFirstServicePerson(user.getUsername());
                    }
                }
                //单据明细
                tblOrderAuditBillDtl.setId(CommonAcsUtil.generateUUId());
                tblOrderAuditBillDtl.setCreateTime(new Date());
                tblOrderAuditBillDtl.setCreateUser(user.getUsername());
                tblOrderAuditBillDtl.setResponsiblePerson(user.getUsername());
                //单据主表
                tblOrderAuditBill.setDealDtlId(tblOrderAuditBillDtl.getId());
                tblOrderAuditBill.setUpdateTime(new Date());
                tblOrderAuditBill.setUpdateUser(user.getUsername());
                tblOrderAuditBill.setResponsiblePerson(user.getUsername());

                billParams.put("billStatusNo", tblOrderAuditBillDtl.getOrderBillStatusNo());
                List<TblAcsRoleBillStatus> acsRoleBillStatusList = tblAcsRoleBillStatusService.selectByParam(billParams);
                tblOrderAuditBillDtl.setRoleNo(acsRoleBillStatusList.get(0).getRoleNo());
                tblOrderAuditBillDtl.setStatusName("确认");
                tblOrderAuditBillDtl.setUpdateTime(new Date());
                tblOrderAuditBillDtl.setUpdateUser(user.getUsername());

                List<TblOrderAuditBillDtl> orderAuditBillDtlList = tblOrderAuditBillDtlMapper.selectByParam(billParams);
                tblOrderAuditBillDtl.setOrderField(orderAuditBillDtlList.get(0).getOrderField() + 1);
                tblOrderAuditBillDtl.setLastEffectiveId(orderAuditBillList.get(0).getDealDtlId());
                //插入操作日志
                tblOrderAuditBillDtlMapper.insert(tblOrderAuditBillDtl);
                //更新主表信息
                tblOrderAuditBillMapper.updateByBillNo(tblOrderAuditBill);
//                log.info("订单稽核单据处理，批量导入数据成功===true，单据编码billNo={}",billNo);
                succList.add(billNo);
            }
        }
        log.info("订单稽核单据处理，批量导入数据结束====，succList={}，failList={}", succList, failList);
    }
}

